package com.ywl.mvcframework.servlet;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ywl.mvcframework.actionform.ActionForm;
import com.ywl.mvcframework.config.ActionConfig;
import com.ywl.mvcframework.config.FormbeanConfig;
import com.ywl.mvcframework.util.MvcConfigUtil;
import com.ywl.mvcframework.util.RequestParamUtil;

/**
 * 分发器处理所有的*.do请求
 * @author yangwenle
 *
 */
public class DispatcherServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		//获取访问路径
		String uri = req.getRequestURI();
		String contextPath = req.getContextPath();
		
		//获得path
		int endIndex = uri.indexOf(".");
		String path = uri.substring(contextPath.length(),endIndex);
		
		//获取参数method,约定以method的值作为访问方法
		String methodParam = req.getParameter("method");
		if(methodParam == null || "".equals(methodParam)){
			methodParam = "index";
		}
		
		//调用对应的控制器的具体方法
		ServletContext application= this.getServletContext();
		Map<String,ActionConfig> configMap = (Map<String,ActionConfig>)application.getAttribute("actionConfigMap");
		Map<String,FormbeanConfig> fbConfigMap = (Map<String,FormbeanConfig>)application.getAttribute("formbeanConfigMap");
		ActionConfig ac = configMap.get(path);
		
		if(ac == null){
			throw new ServletException(uri+" not fund！");
		}
		
		//利用反射调用Action
		try {
			Class actionClass = Class.forName(ac.getClassName());
			Method[] allMethod = actionClass.getDeclaredMethods();
			String mName = "";
			Class pvec[] = null;
			Class returnType = null;
			
			
			for(Method mm : allMethod){
				mName = mm.getName();
				if(mName.equals(methodParam)){
					
					//反射取参数
					pvec = mm.getParameterTypes();
			        for (int j = 0; j < pvec.length; j++) 
			          System.out.println("param #" + j + " " + pvec[j]); 
			        
					//反射取返回类型
			        returnType = mm.getReturnType();
			        System.out.println("return type = " + mm.getReturnType());
			        break;
				}
			}
			
			//参数值设置
			Method method = null;
			if(pvec == null || pvec.length == 0){
				method = actionClass.getMethod(methodParam);
			}else{
				method = actionClass.getMethod(methodParam, pvec);
			}

			//根据类型设置参数
			List<Object> param = new ArrayList<Object>();
			if(pvec != null && pvec.length > 0){
				for(Class cla : pvec){
					String claName = cla.getName();
					if("javax.servlet.http.HttpServletRequest".equals(claName)){
						param.add(req);
					}else if("javax.servlet.http.HttpServletResponse".equals(claName)){
						param.add(resp);
					}else if("com.ywl.mvcframework.actionform.ActionForm".equals(claName)){
						
						//利用反射实例化和取值
						String fmbean = ac.getFmbean();
						String formName = "com.ywl.mvcframework.actionform.ActionForm";
						if(fmbean != null){
							FormbeanConfig fc = fbConfigMap.get(fmbean);
							if(fc != null){
								formName = fc.getType();
							}
						}
						
						Class actionFormClass = Class.forName(formName);
						//通过一个工具类从request里面将值放到objForm
						ActionForm objForm = RequestParamUtil.generateActionForm(req, actionFormClass);
						
						param.add(objForm);
					}
				}
			}
			
			if(returnType.getName().equals("java.lang.String")){
				String forward = (String)method.invoke(actionClass.newInstance(), param.toArray());
				
				if(forward != null && forward.startsWith("redirect:")){
					
					//重定向
					forward = forward.substring("redirect:".length(), forward.length());
					resp.sendRedirect(forward);
				}else if(forward != null){
					
					//进行转发
					req.setAttribute("uri",path);
					req.getRequestDispatcher(forward).forward(req, resp);
				}
			}else if(returnType.getName().equals("void")){
				method.invoke(actionClass.newInstance(), param.toArray());
			}
		} catch (ClassNotFoundException | NoSuchMethodException 
				| SecurityException | IllegalAccessException | 
				IllegalArgumentException | InvocationTargetException | InstantiationException e) {
			e.printStackTrace();
			throw new ServletException();
		}
		
		
		
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String contextConfigLocation = config.getInitParameter("contextConfigLocation");
		System.out.println(contextConfigLocation);
		
		//存储
		ServletContext application= this.getServletContext();
		Map<String,ActionConfig> actionConfigMap = (Map<String,ActionConfig>)application.getAttribute("actionConfigMap");
		Map<String,FormbeanConfig> formbeanConfigMap = (Map<String,FormbeanConfig>)application.getAttribute("formbeanConfigMap");
		
		if(actionConfigMap == null){
			actionConfigMap = new HashMap<String,ActionConfig>();
		}
		if(formbeanConfigMap == null){
			formbeanConfigMap = new HashMap<String,FormbeanConfig>();
		}
		
		String[] paths = contextConfigLocation.split(",");
		String path = "";
		for(int i=0; i<paths.length; i++){
			path = paths[i];
			//解析xml返回map将map放到Application中
			String projectPath = this.getServletContext().getRealPath("/");
			MvcConfigUtil.readConfig(actionConfigMap, formbeanConfigMap, projectPath+path);
		}
		
		//存储
		application.setAttribute("actionConfigMap",actionConfigMap);
		application.setAttribute("formbeanConfigMap",formbeanConfigMap);
	}

	
}
